#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#include <stdio.h>
#include <fcntl.h>


#define BUF_SIZE 1024


///struct sembuf
//{
///	short sem_num;   /* semaphore number: 0 = first */
///	short sem_op;    /* semaphore operation */
///	short sem_flg;   /* operation flags */
//}

union semun
{
	int val;                /* value for SETVAL */
	struct semid_ds *buf;   /* buffer for IPC_STAT & IPC_SET */
	ushort *array;          /* array for GETALL & SETALL */
	struct seminfo *__buf;  /* buffer for IPC_INFO */
	void *__pad;
};

int main( int argc, char **argv)
{
	if ( argc != 2)
	{
		printf("Wrong arguments\n");
		exit(1);
	}
	
	int fd_in = open( (char*)argv[1], O_RDONLY);
	if ( fd_in == -1)
	{
		printf("Can't open file: %s",(char*)argv[1]);
		exit(0);
	}
	
	
	open( ".for_keys", O_CREAT | 0644);
///////////////////////////////////////////////
	key_t key_sem_common_read   = ftok( ".for_keys", 1);
	key_t key_sem_common_write  = ftok( ".for_keys", 2);
	
	key_t key_shm_common = ftok( ".for_keys", 5);
	
	int sem_id_common_read  = semget( key_sem_common_read ,1,IPC_CREAT | 0644);
	int sem_id_common_write = semget( key_sem_common_write,1,IPC_CREAT | 0644);
	
	int sem_id_buffer_read  = semget( IPC_PRIVATE   ,1,IPC_CREAT | 0644);
	int sem_id_buffer_write = semget( IPC_PRIVATE   ,1,IPC_CREAT | 0644);
	
	int shm_id_common = shmget( key_shm_common, 4*sizeof( int), IPC_CREAT | 0644);
	int shm_id_buffer = shmget( IPC_PRIVATE   , BUF_SIZE      , IPC_CREAT | 0644);
	int shm_id_count  = shmget( IPC_PRIVATE   , sizeof(int)   , IPC_CREAT | 0644);
	
	
	int  * ptr_shm_common = (int* ) shmat( shm_id_common, NULL, NULL);
	char * ptr_shm_buffer = (char*) shmat( shm_id_buffer, NULL, NULL);
	int  * ptr_shm_count  = (int* ) shmat( shm_id_count , NULL, NULL);
////////////////////////////////////////////////
	struct sembuf sem_buf;
	union semun sem_opts;
	
	sem_buf.sem_num = 0;
	sem_buf.sem_flg = IPC_NOWAIT;
	sem_buf.sem_op  = 1;
	
	struct sembuf sem_buf_inc, sem_buf_dec;
	
	sem_buf_inc.sem_num = 0;
	sem_buf_inc.sem_flg = SEM_UNDO;
	sem_buf_inc.sem_op  = 1;
	
	sem_buf_dec.sem_num = 0;
	sem_buf_dec.sem_flg = SEM_UNDO;
	sem_buf_dec.sem_op  = -1;	
////////////////////////////////////////////////
	semop ( sem_id_common_write, &sem_buf_dec,1);
		ptr_shm_common[ 0] = shm_id_buffer;
		ptr_shm_common[ 1] = shm_id_count;
		ptr_shm_common[ 2] = sem_id_buffer_read;
		ptr_shm_common[ 3] = sem_id_buffer_write;
	semop ( sem_id_common_write, &sem_buf_inc,1);
	
	semop ( sem_id_common_read, &sem_buf_inc,1);
////////////////////////////////////////////////
	
	int read_count;
	do
	{	
		semop( sem_id_buffer_write, &sem_buf_dec,1);
			read_count = read( fd_in, ptr_shm_buffer, BUF_SIZE);
			if ( read_count == -1)
			{
				perror("In read error");
			}
			else
				*ptr_shm_count = read_count;
		semop( sem_id_buffer_write, &sem_buf_inc, 1);
		
		semop( sem_id_buffer_read , &sem_buf_inc, 1);
	}
	while( read_count);
	
	
//	semctl( semid, 0, IPC_RMID, 0);
}